package com.duoqin.syncassistant.viewmodel;

import android.app.Application;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.util.Log;
import android.widget.Toast;

import com.android.contacts.vcard.ExportProcessor;
import com.duoqin.common.data.DefaultResponse;
import com.duoqin.common.data.remote.ApiClient;
import com.duoqin.syncassistant.R;
import com.duoqin.syncassistant.Utils;
import com.duoqin.syncassistant.data.BackupFileDownloadResponse;
import com.duoqin.syncassistant.data.BackupFileRestoreResponse;
import com.duoqin.syncassistant.data.remote.ApiInterface;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class VCardSyncViewModel extends BaseViewModel {
    private static final String TAG = "duoqin_VCardSync";

    private ApiInterface mApiInterface;
    private MutableLiveData<DefaultResponse> mVCardBackupResponse;
    private MutableLiveData<BackupFileRestoreResponse> mVCardRestoreResponse;
    private MutableLiveData<DefaultResponse> mVCardDeleteResponse;
    private MutableLiveData<BackupFileDownloadResponse> mDownloadVCardResponse;

    public VCardSyncViewModel(@NonNull Application application) {
        super(application);
        mApiInterface = ApiClient.getClient().create(ApiInterface.class);
    }

    public LiveData<DefaultResponse> vcardBackupResponse() {
        if (mVCardBackupResponse == null) {
            mVCardBackupResponse = new MutableLiveData<>();
        }
        return mVCardBackupResponse;
    }

    public void backupVCard(String token, int count, String vCardPath) {
        Log.d(TAG, "backupVCard");
        if (vCardPath == null) return;
        byte[] vCardBytes = null;
        if (vCardPath != null) {
            try {
                FileInputStream fis = new FileInputStream(vCardPath);
                vCardBytes = new byte[fis.available()];
                fis.read(vCardBytes);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (vCardBytes == null) return;

        String hash = Utils.md5(vCardBytes);
        Log.d(TAG, "hash = " + hash);
        RequestBody vCardBody = RequestBody.create(MediaType.parse("application/octet-stream"),
                vCardBytes);
        final Call<DefaultResponse> call = mApiInterface.vcardBackup(token, hash, count, vCardBody);
        if (call != null) {
            call.enqueue(new Callback<DefaultResponse>() {
                @Override
                public void onResponse(Call<DefaultResponse> call,
                                       Response<DefaultResponse> response) {
                    Log.d(TAG, "onResponse = " + response);
                    if (response != null && mVCardBackupResponse != null) {
                        Log.d(TAG, "body " + response.body());
                        if (200 == response.code()) {
                            mVCardBackupResponse.setValue(response.body());
                        } else {
                            try {
                                String errorString = response.errorBody().string();
                                Log.w(TAG, "error " + errorString);
                                JSONObject jsonObject = new JSONObject(errorString);
                                DefaultResponse errorResponse = new DefaultResponse();
                                errorResponse.setCode(jsonObject.getInt("code"));
                                errorResponse.setMsg(jsonObject.getString("msg"));
                                mVCardBackupResponse.setValue(errorResponse);
                            } catch (IOException e) {
                                e.printStackTrace();
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }

                @Override
                public void onFailure(Call<DefaultResponse> call, Throwable t) {
                    Log.e(TAG, t.toString());
                    Toast.makeText(getApplication(), R.string.network_error_default,
                            Toast.LENGTH_SHORT).show();
                    if (mVCardBackupResponse != null) {
                        mVCardBackupResponse.setValue(null);
                    }
                }
            });
        }
    }

    public LiveData<BackupFileRestoreResponse> vcardRestoreResponse() {
        if (mVCardRestoreResponse == null) {
            mVCardRestoreResponse = new MutableLiveData<>();
        }
        return mVCardRestoreResponse;
    }

    public void getVcardRestoreInfo(String token, int size, int page) {
        Log.d(TAG, "getVcardRestoreInfo");
        final Call<BackupFileRestoreResponse> call = mApiInterface.vcardRestore(token, size, page);
        if (call != null) {
            call.enqueue(new Callback<BackupFileRestoreResponse>() {
                @Override
                public void onResponse(Call<BackupFileRestoreResponse> call,
                                       Response<BackupFileRestoreResponse> response) {
                    Log.d(TAG, "onResponse = " + response);
                    if (response != null && mVCardRestoreResponse != null) {
                        Log.d(TAG, "body " + response.body());
                        if (200 == response.code()) {
                            mVCardRestoreResponse.setValue(response.body());
                        } else {
                            try {
                                String errorString = response.errorBody().string();
                                Log.w(TAG, "error " + errorString);
                                JSONObject jsonObject = new JSONObject(errorString);
                                BackupFileRestoreResponse errorResponse = new BackupFileRestoreResponse();
                                errorResponse.setCode(jsonObject.getInt("code"));
                                errorResponse.setMsg(jsonObject.getString("msg"));
                                mVCardRestoreResponse.setValue(errorResponse);
                            } catch (IOException e) {
                                e.printStackTrace();
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }

                @Override
                public void onFailure(Call<BackupFileRestoreResponse> call, Throwable t) {
                    Log.e(TAG, t.toString());
                    Toast.makeText(getApplication(), R.string.network_error_default,
                            Toast.LENGTH_SHORT).show();
                    if (mVCardRestoreResponse != null) {
                        mVCardRestoreResponse.setValue(null);
                    }
                }
            });
        }
    }

    public LiveData<DefaultResponse> deleteVCardResponse() {
        if (mVCardDeleteResponse == null) {
            mVCardDeleteResponse = new MutableLiveData<>();
        }
        return mVCardDeleteResponse;
    }

    public void deleteVCard(String token, String id) {
        Log.d(TAG, "deleteVCard");
        final Call<DefaultResponse> call = mApiInterface.deleteVCard(token, id);
        if (call != null) {
            call.enqueue(new Callback<DefaultResponse>() {
                @Override
                public void onResponse(Call<DefaultResponse> call,
                                       Response<DefaultResponse> response) {
                    Log.d(TAG, "onResponse = " + response);
                    if (response != null && mVCardDeleteResponse != null) {
                        if (200 == response.code()) {
                            mVCardDeleteResponse.setValue(response.body());
                            Log.d(TAG, "body " + response.body());
                        } else {
                            try {
                                String errorString = response.errorBody().string();
                                Log.w(TAG, "error " + errorString);
                                JSONObject jsonObject = new JSONObject(errorString);
                                DefaultResponse errorResponse = new DefaultResponse();
                                errorResponse.setCode(jsonObject.getInt("code"));
                                errorResponse.setMsg(jsonObject.getString("msg"));
                                mVCardDeleteResponse.setValue(errorResponse);
                            } catch (IOException e) {
                                e.printStackTrace();
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }

                @Override
                public void onFailure(Call<DefaultResponse> call, Throwable t) {
                    Log.e(TAG, t.toString());
                    Toast.makeText(getApplication(), R.string.network_error_default,
                            Toast.LENGTH_SHORT).show();
                    if (mVCardDeleteResponse != null) {
                        mVCardDeleteResponse.setValue(null);
                    }
                }
            });
        }
    }

    public LiveData<BackupFileDownloadResponse> downloadVCardResponse() {
        if (mDownloadVCardResponse == null) {
            mDownloadVCardResponse = new MutableLiveData<>();
        }
        return mDownloadVCardResponse;
    }

    public void downloadVCard(String vCardUrl, final String vCardHash) {
        Log.d(TAG, "downloadVCard");
        final Call<ResponseBody> call = mApiInterface.downloadVCard(vCardUrl);
        if (call != null) {
            call.enqueue(new Callback<ResponseBody>() {
                @Override
                public void onResponse(Call<ResponseBody> call,
                                       Response<ResponseBody> response) {
                    Log.d(TAG, "onResponse = " + response);
                    if (response != null && mDownloadVCardResponse != null) {
                        BackupFileDownloadResponse vCardDownloadResponse = new BackupFileDownloadResponse();
                        if (200 == response.code()) {
                            try {
                                InputStream is = response.body().byteStream();
                                File file = new File(getApplication().getCacheDir(),
                                        ExportProcessor.VCARD_FILE_NAME);
                                if (file.exists()) {
                                    file.delete();
                                }
                                FileOutputStream fos = new FileOutputStream(file);
                                BufferedInputStream bis = new BufferedInputStream(is);
                                byte[] buffer = new byte[1024];
                                int len;
                                MessageDigest digest = MessageDigest.getInstance("MD5");
                                while ((len = bis.read(buffer)) != -1) {
                                    fos.write(buffer, 0, len);
                                    fos.flush();
                                    digest.update(buffer, 0, len);
                                }
                                bis.close();
                                fos.close();
                                is.close();
                                Log.d(TAG, "vCard received, path = " + file.getAbsolutePath());

                                byte[] result = digest.digest();
                                String md5_computed = Utils.bytesToHex(result);
                                if (md5_computed.matches(vCardHash)) {
                                    Log.d(TAG, "vCard hash is valid");
                                    vCardDownloadResponse.setCode(SERVER_RESULT_SUCCESS);
                                    vCardDownloadResponse.setPath(file.getAbsolutePath());
                                    mDownloadVCardResponse.setValue(vCardDownloadResponse);
                                } else {
                                    Log.d(TAG, "vCard hash is invalid");
                                    file.delete();
                                    vCardDownloadResponse.setCode(LOCAL_ERROR_INVALID_HASH);
                                    mDownloadVCardResponse.setValue(vCardDownloadResponse);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                                vCardDownloadResponse.setCode(LOCAL_ERROR_DEFAULT);
                                mDownloadVCardResponse.setValue(vCardDownloadResponse);
                            }
                        } else {
                            try {
                                String errorString = response.errorBody().string();
                                Log.w(TAG, "error " + errorString);
                                JSONObject jsonObject = new JSONObject(errorString);
                                vCardDownloadResponse.setCode(jsonObject.getInt("code"));
                                vCardDownloadResponse.setMsg(jsonObject.getString("msg"));
                                mDownloadVCardResponse.setValue(vCardDownloadResponse);
                            } catch (IOException e) {
                                e.printStackTrace();
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }

                @Override
                public void onFailure(Call<ResponseBody> call, Throwable t) {
                    Log.e(TAG, t.toString());
                    Toast.makeText(getApplication(), R.string.network_error_default,
                            Toast.LENGTH_SHORT).show();
                    if (mDownloadVCardResponse != null) {
                        mDownloadVCardResponse.setValue(null);
                    }
                }
            });
        }
    }
}
